import java.io.*;
import java.net.*;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonArray;

/**
 * 基于套接字的天气API服务实现
 * 连接到自定义TCP套接字服务器作为备份天气数据源
 */
public class SocketWeatherAPIService implements WeatherAPIService {
    
    private String serverHost;
    private int serverPort;
    private UserPreferences userPreferences;
    private boolean serviceAvailable = false;
    private long lastConnectionTest = 0;
    private static final long CONNECTION_TEST_CACHE_MS = 60000; // 1分钟缓存
    private static final int SOCKET_TIMEOUT = 5000; // 5秒超时
    
    public SocketWeatherAPIService(UserPreferences userPreferences) {
        this(userPreferences, "localhost", 8888);
    }
    
    public SocketWeatherAPIService(UserPreferences userPreferences, String host, int port) {
        this.userPreferences = userPreferences;
        this.serverHost = host;
        this.serverPort = port;
    }
    
    @Override
    public String getSourceId() {
        return "socket-backup";
    }
    
    @Override
    public String getDisplayName() {
        return "Socket Backup Server";
    }
    
    @Override
    public boolean isServiceAvailable() {
        // 缓存连接测试结果
        long currentTime = System.currentTimeMillis();
        if (currentTime - lastConnectionTest > CONNECTION_TEST_CACHE_MS) {
            serviceAvailable = testConnection() > 0;
            lastConnectionTest = currentTime;
        }
        return serviceAvailable;
    }
    
    @Override
    public String getBaseURL() {
        return "socket://" + serverHost + ":" + serverPort;
    }
    
    @Override
    public long testConnection() {
        try {
            long startTime = System.currentTimeMillis();
            
            try (Socket socket = new Socket()) {
                socket.connect(new InetSocketAddress(serverHost, serverPort), SOCKET_TIMEOUT);
                socket.setSoTimeout(SOCKET_TIMEOUT);
                
                try (PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
                     BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
                    
                    // 发送测试请求
                    out.println("TEST:connection");
                    String response = in.readLine();
                    
                    long endTime = System.currentTimeMillis();
                    long latency = endTime - startTime;
                    
                    if ("PONG".equals(response)) {
                        return latency;
                    }
                }
            }
            
            return -1;
            
        } catch (Exception e) {
            System.err.println("Socket server connection test failed: " + e.getMessage());
            return -1;
        }
    }
    
    @Override
    public boolean isLocationSupported(Location location) {
        // Socket服务器支持任何城市名称
        return location != null && location.getCity() != null && !location.getCity().trim().isEmpty();
    }
    
    @Override
    public APISourceInfo.APIStatus getAPIStatus() {
        if (!isServiceAvailable()) {
            return APISourceInfo.APIStatus.ERROR;
        }
        
        long latency = testConnection();
        if (latency < 0) {
            return APISourceInfo.APIStatus.ERROR;
        } else if (latency > 3000) {
            return APISourceInfo.APIStatus.ERROR;
        } else {
            return APISourceInfo.APIStatus.ONLINE;
        }
    }
    
    @Override
    public int getPriority() {
        return 3; // 最低优先级，作为最后的备份源
    }
    
    @Override
    public String getAPILimits() {
        return "Socket Backup Server - No API limits (local)";
    }
    
    @Override
    public WeatherData getCurrentWeather(Location location) throws RuntimeException {
        if (!isServiceAvailable()) {
            throw new RuntimeException("Socket weather server is not available");
        }
        
        if (!isLocationSupported(location)) {
            throw new RuntimeException("Location not supported: " + 
                (location != null ? location.getCity() : "null"));
        }
        
        try {
            String response = sendSocketRequest("WEATHER:" + location.getCity());
            return parseCurrentWeatherResponse(response);
            
        } catch (Exception e) {
            serviceAvailable = false;
            throw new RuntimeException("Socket server error: " + e.getMessage());
        }
    }
    
    @Override
    public WeatherData[] getForecast(Location location, int days) throws RuntimeException {
        if (!isServiceAvailable()) {
            throw new RuntimeException("Socket weather server is not available");
        }
        
        if (!isLocationSupported(location)) {
            throw new RuntimeException("Location not supported: " + 
                (location != null ? location.getCity() : "null"));
        }
        
        try {
            String response = sendSocketRequest("FORECAST:" + location.getCity() + ":" + days);
            return parseForecastResponse(response);
            
        } catch (Exception e) {
            serviceAvailable = false;
            throw new RuntimeException("Socket server forecast error: " + e.getMessage());
        }
    }
    
    /**
     * 发送套接字请求
     */
    private String sendSocketRequest(String request) throws IOException {
        try (Socket socket = new Socket()) {
            socket.connect(new InetSocketAddress(serverHost, serverPort), SOCKET_TIMEOUT);
            socket.setSoTimeout(SOCKET_TIMEOUT);
            
            try (PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
                 BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
                
                out.println(request);
                String response = in.readLine();
                
                if (response == null) {
                    throw new IOException("No response from socket server");
                }
                
                return response;
            }
        }
    }
    
    /**
     * 解析当前天气响应
     */
    private WeatherData parseCurrentWeatherResponse(String response) {
        try {
            JsonObject jsonObj = JsonParser.parseString(response).getAsJsonObject();
            
            // 检查错误
            if (jsonObj.has("error")) {
                String error = jsonObj.get("error").getAsString();
                throw new RuntimeException("Socket server error: " + error);
            }
            
            JsonObject main = jsonObj.getAsJsonObject("main");
            JsonObject wind = jsonObj.getAsJsonObject("wind");
            
            double temp = main.get("temp").getAsDouble();
            double humidity = main.get("humidity").getAsDouble();
            double windSpeed = wind.get("speed").getAsDouble();
            String description = jsonObj.get("description").getAsString() + " (Backup)";
            
            return new WeatherData(temp, humidity, windSpeed, description, "Current", userPreferences);
            
        } catch (Exception e) {
            if (e instanceof RuntimeException) {
                throw e;
            }
            throw new RuntimeException("Failed to parse socket weather data: " + e.getMessage());
        }
    }
    
    /**
     * 解析预报响应
     */
    private WeatherData[] parseForecastResponse(String response) {
        try {
            JsonObject jsonObj = JsonParser.parseString(response).getAsJsonObject();
            
            // 检查错误
            if (jsonObj.has("error")) {
                String error = jsonObj.get("error").getAsString();
                throw new RuntimeException("Socket server error: " + error);
            }
            
            JsonArray forecast = jsonObj.getAsJsonArray("forecast");
            WeatherData[] forecastData = new WeatherData[forecast.size()];
            
            for (int i = 0; i < forecast.size(); i++) {
                JsonObject dayData = forecast.get(i).getAsJsonObject();
                JsonObject main = dayData.getAsJsonObject("main");
                JsonObject wind = dayData.getAsJsonObject("wind");
                
                double temp = main.get("temp").getAsDouble();
                double humidity = main.get("humidity").getAsDouble();
                double windSpeed = wind.get("speed").getAsDouble();
                String description = dayData.get("description").getAsString() + " (Backup)";
                String date = dayData.get("date").getAsString();
                
                forecastData[i] = new WeatherData(temp, humidity, windSpeed, description, 
                    "Forecast " + date, userPreferences);
            }
            
            return forecastData;
            
        } catch (Exception e) {
            if (e instanceof RuntimeException) {
                throw e;
            }
            throw new RuntimeException("Failed to parse socket forecast data: " + e.getMessage());
        }
    }
    
    /**
     * 设置服务器地址
     */
    public void setServerAddress(String host, int port) {
        this.serverHost = host;
        this.serverPort = port;
        // 重置连接测试缓存
        lastConnectionTest = 0;
        System.out.println("Socket server address updated to " + host + ":" + port);
    }
    
    /**
     * 获取服务器地址信息
     */
    public String getServerAddress() {
        return serverHost + ":" + serverPort;
    }
} 